using System;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
using System.Threading;
using System.Text;



namespace ChatServer
{
	class MainClass
	{
		public static bool Ondebug = false;

		// Danh sách đã sẵng sàng kết nối ;
		public static Dictionary <int,CGlobalStructure.UserInfo> listconnected = new Dictionary<int,CGlobalStructure.UserInfo>();
		// Danh sách trong trạng thái chờ login;
		public static List <Socket> listbindding = new List<Socket>();

		// chứa socket kết nối lần gần đây nhất
		public static Socket lastsock;
		/// <summary>
		///  Thời gian chờ kết nối, nếu sau thời gian chờ phản hồi kết nối sẽ bị drop
		/// </summary>
		public static int defaultsock_timeout = 6000;

		static Configure _cf = new Configure("config");

		public static String listenip = "112.213.87.154";
		public static string hello_packet = "Chào mừng đến với server chat ! \n";
		public static String http_server ="server1.1158.vn/minichat/";
		public static string http_avatars = "server1.1158.vn/minichat/resources/avatars/";
		public static db _d;
		public static int buffersize = 1024;

		public static void Main (string[] args)
		{
#if DEBUG
			Ondebug = true;
#endif
			// Read config 
			listenip = _cf.GetTag("listen_on");
			buffersize = int.Parse(_cf.GetTag("buffer_size"));
			String hlpk = _cf.GetTag("hello_packet");
			defaultsock_timeout = int.Parse(_cf.GetTag("defaultsock_timeout"));		
			if(defaultsock_timeout < 2000){defaultsock_timeout=2000;}
			listenip = _cf.GetTag("listen_on");
			
			if(hlpk != "" ){hello_packet = hlpk + "\n";}

			//
			Console.Title = "  >> Chating server starting ... ";
			_d = new db ();
			Thread debugclient = new Thread(
				new ThreadStart(DebugClient)
			);
			debugclient.SetApartmentState(ApartmentState.MTA);
			debugclient.Priority = ThreadPriority.Highest;
			debugclient.Start();
			Socket s = new Socket(AddressFamily.InterNetwork, 
			                      SocketType.Stream, ProtocolType.Tcp);
			IPAddress hostIP = (Dns.Resolve(listenip)).AddressList[0];
			IPEndPoint ep = new IPEndPoint(hostIP, 5203);
			s.Bind(ep); 
			s.Listen(0);
			UserManager.StartServer();
			do {
				Socket accepsocks = s.Accept ();
				listbindding.Add (accepsocks);
				lastsock = accepsocks;
				Thread t = new Thread (
					new ThreadStart (WailtMessage)
				);
				t.SetApartmentState (ApartmentState.MTA);
				t.Priority =ThreadPriority.Lowest;
				t.Start ();			
				Console.WriteLine ("Nhan ket noi tu {0}", accepsocks.RemoteEndPoint.ToString ());
			} while(true);
				
		}


		static void WailtMessage()
		{
			if (lastsock == null) {
				return;
			}
			// 
			bool islogged  = false;
			int uid=-1;

			Socket sock = lastsock;
			// dọn dep sock
			lastsock = null;
			//  get connect time
			int cntime = Environment.TickCount;
			// goi goi chao mung
			sock.Send (Encoding.UTF8.GetBytes (hello_packet));
			Byte []contextbytes=null;
			do {
				Byte  [] bytes = new byte[buffersize]; 
				try
				{
					int i = sock.Receive (bytes);
					Array.Resize<Byte> (ref bytes,i);
					if(i < buffersize)
					{
						String datatext= "" ;
						if(contextbytes == null)
						{
							datatext =  (Encoding.UTF8.GetString (bytes));
							bytes = null;
						}else{
							datatext =  (Encoding.UTF8.GetString (contextbytes));
							contextbytes = null;
						}
						Server.ProcessMessage(datatext,sock,ref islogged,ref uid);
					}
					else
					{
						if (contextbytes == null)
						{
							contextbytes = new byte[buffersize-1];
							bytes.CopyTo(contextbytes,0);
							bytes = null;
						}else
						{
							Array.Resize(ref contextbytes,contextbytes.Length + i);
							bytes.CopyTo(contextbytes,contextbytes.Length - i);
							bytes = null;
						}

					}
					if(i == 0){System.Threading.Thread.Sleep (100);}

				}catch(Exception ex)
				{
					Ullity.Log(ex.Message);
					try{lastsock.Close();}catch{}
					return;// close sock
				}

			} while(true);

		}

		/// <summary>
		///  Thread quản lý kết nối client
		///  Drop các kết nối quá hạn , dọn dẹp rác, 
		/// </summary>
		public static void DebugClient()
		{
			while(true){
				try{
				foreach ( var uinfok in listconnected)
				{
					CGlobalStructure.UserInfo uinfo = uinfok.Value;
						// nếu sau 1/2 thời gian chờ ping mà ko nhận đc reply từ client thì client bị disconnect
						//if(!Ondebug){ // Vô hiệu timeout khi debug để test server
								if(uinfo.WailPing == true  && Environment.TickCount - uinfo.LastPing > defaultsock_timeout/2)
									{
										Ullity.Log("Client " + uinfo.UserName + " timeout, disconnected . Clear thread and data ",3);
									
										try{
										UserManager.SetUserOffline(uinfo.UserID);
										Server.UpdateUserIfo(uinfo.UserID);
											uinfo.Sock.Close();
										}catch{Ullity.Log("Close socket failed " + uinfo.UserName,2);}
										listconnected.Remove(uinfok.Key);
										logOnlineUser();
										}
						//}
					if( Environment.TickCount - uinfo.LastPing > defaultsock_timeout){
						try{
								uinfo.LastPing = Environment.TickCount;
								Server.Send("PING:" + Environment.TickCount,uinfo.Sock);
								uinfo.WailPing = true;
						}catch{
							Ullity.Log("Client " + uinfo.UserName + " disconnect . Clear thread and data ",3);
							try{
									UserManager.SetUserOffline(uinfo.UserID);
									Server.UpdateUserIfo(uinfo.UserID);
									uinfo.Sock.Close();
							}catch{Ullity.Log("Close socket failed " + uinfo.UserName,2);}
							listconnected.Remove(uinfok.Key);						   
							logOnlineUser();
						}
					}
					}}
				catch(Exception ex){
					Ullity.Log(ex.Message,3);
				}
				Console.Title = DateTime.Now.ToLongTimeString();
				Thread.Sleep(1000);
			}
		}

		public static void logOnlineUser()
		{
			Ullity.Log("Online : " + listconnected.Count + " client",3);
		}

	}
}
